/**
 * 
 */
package com.higherground.api.domain;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Properties;

import com.higherground.api.HighergroundConstants;
import com.higherground.api.exception.HighergroundException;
import com.higherground.api.exception.ImplementationNotFoundException;

/**
 * @author jimmy
 * 
 */
public class DomainFactory {

	private static Properties domainImpls = null;

	private static final DomainFactory INSTANCE = new DomainFactory();

	static {
		domainImpls = new Properties();
		try {
			InputStream stream = DomainFactory.class
					.getResourceAsStream(HighergroundConstants.DOMAIN_IMPL_FILE_PATH);
			domainImpls.load(stream);
		} catch (IOException ioException) {
			// TODO: handle exception
			throw new HighergroundException(
					"Exception occured while loading domain implementation properties file.",
					ioException);
		}
	}

	/**
	 * 
	 */
	public DomainFactory() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @return the instance
	 */
	public static DomainFactory getInstance() {
		return INSTANCE;
	}

	/**
	 * get implementation name by interface name
	 * 
	 * @param interfaceName
	 * @return
	 */
	public String getImplementationName(String interfaceName) {
		return domainImpls.getProperty(interfaceName);
	}

	/**
	 * get implementation class by interface
	 * 
	 * @param domainInterface
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <I extends IDomain, T extends I> Class<T> getImplClass(
			Class<I> domainInterface) {
		Class<T> implClass = null;
		String implName = getImplementationName(domainInterface.getName());

		if (implName == null) {
			throw new ImplementationNotFoundException("Implementation for "
					+ domainInterface.getName() + " not found");
		}

		try {
			implClass = (Class<T>) Class.forName(implName);
		} catch (ClassNotFoundException e) {
			throw new HighergroundException(e);
		}
		return implClass;
	}

	/**
	 * get domain object by domain interface
	 * @param domainInterface
	 * @return
	 */
	public <I extends IDomain, T extends I> T getDomainObject(
			Class<I> domainInterface) {
		T object = null;

		try {
			Class<T> clazz = getImplClass(domainInterface);
			Constructor<T> constr = clazz.getConstructor();
			object = constr.newInstance();
		} catch (Exception e) {
			// TODO: handle exception
			throw new HighergroundException(e);
		}

		return object;
	}

}
